/*
 * This file is part of b.AMP.
 *
 * b.AMP is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * b.AMP is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with b.AMP.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "control_config.hpp"
#include "config.hpp"

#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <boost/regex.hpp>

#include <string>
#include <cassert>
#include <cstdlib>

namespace pt = boost::property_tree;
namespace fs = boost::filesystem;

std::string bamp::ControlConfig::replaceEnvVar(const std::string& str)
{
    const boost::regex e("\\$\\((\\w+)\\)"); // $(VAR)

    std::string::const_iterator start = str.begin();
    std::string::const_iterator end   = str.end();
    boost::smatch match;
    std::string output;
    while (boost::regex_search(start, end, match, e))
    {
        // Append the text before the match
        output.append(start, match[0].first);

        // There should be exactly one captured string: match[1],
        // which contains the variable name (match[0] contains the
        // whole match).
        assert(match.size() == 2);

        // Append the environment variable's value, if it exists.
        std::string varName = match[1];
        char* varValue = getenv(varName.c_str());
        if (varValue != NULL)
        {
            output.append(varValue);
        }
        
        // Advance after the match
        start = match[0].second;
    }

    // Append the end of the string
    output.append(start, end);
    
    return output;
}


void bamp::ControlConfig::load(const boost::filesystem::path& file)
{
    reset();

    // Read the file. An exception is thrown if it fails.
    pt::ptree tree;
    read_xml(file.string(), tree);

    // Read the values that come from the config file.
    if (tree.count("logfile"))
        logfile = replaceEnvVar(tree.get<std::string>("logfile"));

    BOOST_FOREACH(pt::ptree::value_type& v, tree)
    {
        if (v.first == "addon")
            addons.insert(replaceEnvVar(v.second.data()));
        else if (v.first == "path")
            path.insert(replaceEnvVar(v.second.data()));
    }
}

void bamp::ControlConfig::save(const boost::filesystem::path& file)
{
    // Put the values into the config file
    pt::ptree tree;
    tree.put("logfile", logfile.string());

    BOOST_FOREACH(const fs::path& name, addons)
    {
        tree.put("addon", name.string());
    }
    BOOST_FOREACH(const fs::path& name, path)
    {
        tree.put("path", name.string());
    }

    // Write the file. An exception is thrown if it fails.
    write_xml(file.string(), tree);
}

void bamp::ControlConfig::reset()
{
    logfile = replaceEnvVar(BAMP_DEFAULT_LOG_FILE);
    addons.clear();
    path.clear();
}
